Questo progetto usa i servizi offerti da FMP per reperire dati finanziari dei principali indici, titoli e indicatori delle borse più importanti del mondo. Oltre a reperire questi dati, li usa per ottenere analisi, processare i risultati e produrre indicatori usati in diversi ambiti come l’analisi finanziario, la valuation e l’analisi del rischio.
Il progetto è stato scritto nel linguaggio R ma può essere portato a qualsiasi linguaggio di programmazione con le dovute modifiche. Oltre a ciò, è stato anche complementato da annotazioni che possono essere utili alla valutazione di base del codice ed eventuali chiarimenti su passaggi non chiari per gli studenti ancora in preparazione.
Il provider è Financial Modeling Prep e tutti possono ottenere una key gratuita registrandosi al sito.
L’idea alla base del codice è usare i servizi offerti dall’API del sito per trovare dati finanziari da utilizzare nell’analisi o valutazione finanziaria. Attraverso questo script è possibile richiedere anche le metriche e analisi dei dati ricevuti, in modo da poter confrontarle con eventuali analisi già fatti con metodi tradizionali.
ask_api_key <- function()
{
key <- Sys.getenv("FMP_API_KEY")
if (key == "")
{
if (!exists("global_api_key"))
{
global_api_key <<- readline(" Inserisci la tua API Key: ")
Sys.setenv(FMP_API_KEY = global_api_key)
}
return(global_api_key)
}
return(key)
}
Questo script ci permette di creare una funzione che permette di fissare la key con cui faremo le chiamate ed otterremo i risultati richiesti. Il sys.getenv permette di fissare a livello globale questa key. Il doppio condizionale if ci permette di andare a chiedere, ogni volta che qualche script richiederà l’uso della key, se abbiamo già disponibile una key di sistema fissata. Se non esiste, allora la funzione richiederà all’usuario di settare una API key attraverso l’uso della funzione readline e il sys.setenv per fissarla a livello environment.
FMP_CALL <- function(endpoint)
{
api_key <- ask_api_key()
url <- paste0("https://financialmodelingprep.com/api/v3/", endpoint, "?apikey=", api_key)
res <- httr::GET(url)
if (res$status_code == 200)
{
content <- httr::content(res, as = "text")
data <- fromJSON(content)
return(data)
}
else
{
message(" Errore API: ", res$status_code)
return(NULL)
}
}
Avendo settato la key dell’usuario, questa funzione richiede di dare come input cosa si vuole avere dalla chiamata (es: key-metrics/META , profile/AAPL). Il condizionale if serve alla gestione di eventuali errori. Se la chiamata provoca una situazione diversa a code: 200, la funzione avvertirà di un generico errore che avrà bisogno di verifiche da parte dell’usuario.
La richiesta dovrà essere formulata attraverso la funzione “FMP_CALL”, l’input della funzione sarà il codice richiesta (“profile/GOOGL”)
head(FMP_CALL("fx"),10)
## ticker bid ask open low high changes
## 1 AED/AUD 0.43132 0.43232 0.42961 0.42961 0.43273 0.0030041000
## 2 AED/BHD 0.10256 0.10269 0.10256 0.10238 0.10269 -0.0001750619
## 3 AED/CAD 0.39222 0.39222 0.3888 0.3888 0.39235 0.0032783900
## 4 AED/CHF 0.23909 0.24009 0.24015 0.23909 0.24015 -0.0002545666
## 5 AED/DKK 1.87294 1.87529 1.87294 1.86421 1.88249 -0.0069382300
## 6 AED/EUR 0.2511 0.2516 0.25219 0.25045 0.25227 -0.0006644876
## 7 AED/GBP 0.21018 0.21118 0.21097 0.21018 0.21103 -0.0007600000
## 8 AED/ILS 0.98855 0.98855 0.98855 0.98253 1.03584 0.0043467200
## 9 AED/INR 23.659 23.759 23.653 23.653 23.73775 0.0563705100
## 10 AED/JOD 0.19328 0.19328 0.19328 0.19277 0.19362 -0.0002205977
## date
## 1 2025-03-09 13:35:50
## 2 2025-03-09 13:35:50
## 3 2025-03-09 13:35:50
## 4 2025-03-09 13:35:50
## 5 2025-03-09 13:35:50
## 6 2025-03-09 13:35:50
## 7 2025-03-09 13:35:50
## 8 2025-03-09 13:35:50
## 9 2025-03-09 13:35:50
## 10 2025-03-09 13:35:50
Attraverso la richiesta “fx” posso richiedere i prezzi in tempo reale delle principali currencies. L’head viene usato per avere una visione più compressa dell’esempio, richiedendo solo le prime 10 valute scambiate. La lista è ovviamente più ampia.
Ovviamente questi dati possono essere salvati nel nostro environment per poter succesivamente essere usati con altre formule o per altri scopi.
GOOGL_SURPRISES<- FMP_CALL("earnings-surprises/GOOGL")
head(GOOGL_SURPRISES,10)
## date symbol actualEarningResult estimatedEarning
## 1 2025-02-04 GOOGL 2.15 2.12
## 2 2024-10-29 GOOGL 2.12 1.83
## 3 2024-07-23 GOOGL 1.89 1.84
## 4 2024-04-25 GOOGL 1.89 1.51
## 5 2024-01-30 GOOGL 1.64 1.59
## 6 2023-10-24 GOOGL 1.55 1.45
## 7 2023-07-25 GOOGL 1.44 1.34
## 8 2023-04-25 GOOGL 1.17 1.07
## 9 2023-02-02 GOOGL 1.05 1.18
## 10 2022-10-25 GOOGL 1.06 1.25
df<- as.data.frame(GOOGL_SURPRISES)
df$date <- as.numeric(as.POSIXct(df$date))
plot_ly(df, x = ~actualEarningResult, y = ~estimatedEarning, z = ~date,
type = "scatter3d", mode = "markers", marker = list(size = 5, color = df$actualEarningResult, colorscale = "Viridis")) %>%
layout(title = "GOOGL SURPRISES",
scene = list(
xaxis = list(title = "Actual"),
yaxis = list(title = "Estimated"),
zaxis = list(title = "Date")
))
Attraverso la richiesta “earnings-surprises/GOOGL” otteniamo data sulle differenze fra previsioni e actual delle earnings di Google. Salvandole nel nostro environment possiamo poi facilmente maneggiarle per, ad esempio, farne un grafico che migliori la visione e valutazione di questi dati
Il Discounted Cash Flow (DCF) è uno dei metodi di valutazione finanziaria più conosciuti nell’industria. Esso permette di rapportare il valore attuale dell’impresa alle sue previsioni future, permettendo una valutazione più ampia e che tiene conto degli sviluppi futuri ed annessi guadagni.
Il DCF si calcola come:
\[DCF = \sum_{t=1}^{n} \frac{FCF_t}{(1 + WACC)^t} + \frac{TV}{(1 + WACC)^n}\]
La sommatoria contiene al suo interno altri valori che devono essere scorporati in diverse componenti:
1.Free Cash Flow (FCF)
\[ FCF = EBIT \times (1 - T) + D\&A - CAPEX - \Delta NWC \]
2.Weighted Average Cost of Capital (WACC)
\[ WACC = \frac{E}{V} r_E + \frac{D}{V} r_D (1 - T) \]
3.Terminal Value (TV)
\[ TV = \frac{FCF_{n} \times (1 + g)}{WACC - g} \]
Avendo a mente i valori da trovare, possiamo cominciare a richiedere i dati tramite la funzione scritta
CFS_data <- FMP_CALL("cash-flow-statement/MSFT")
fcf <- CFS_data$freeCashFlow
print(fcf)
## [1] 7.4071e+10 5.9475e+10 6.5149e+10 5.6118e+10 4.5234e+10
Richiediamo gli ultimi 5 Cash Flow Statement dell’impresa attraverso la funzione “cash-flow-statement/****” e da essa scorporiamo il free cash flow, che è il primo valore di cui avremo bisogno per calcolare il nostro DCF.
key_metrics <- FMP_CALL("key-metrics/MSFT")
Fin_stat<- FMP_CALL("financial-statement-full-as-reported/MSFT")
sheets<-FMP_CALL("balance-sheet-statement/MSFT")
df<- cbind(key_metrics,Fin_stat,sheets)
beta <- 0.94
Rf <- 0.04
Rm_minus_Rf <- 0.05
tax_rate <- 0.21
Re <-c(Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf)
Rd <- df$interestexpense / df$totalDebt
interest_expense <- df$interestexpense
total_debt <- df$totalDebt
cash <- df$cashAndCashEquivalents
D <- total_debt - cash
E <- key_metrics$marketCap
Ve <- E + D
We <- E / Ve
Wd <- D / Ve
MSFT_WACC <- We * Re + Wd * Rd * (1 - tax_rate)
Anno <- c(2024, 2023, 2022, 2021, 2020)
df_MSFT_WACC <- data.frame(
Anno = Anno,
Costo_Capitale_Proprio = Re,
Costo_Debito = Rd,
Debito_Netto = D,
Peso_Equity = We,
Peso_Debito = Wd,
WACC = MSFT_WACC
)
print(df_MSFT_WACC)
## Anno Costo_Capitale_Proprio Costo_Debito Debito_Netto Peso_Equity Peso_Debito
## 1 2024 0.087 0.04372309 4.8812e+10 0.9858219 0.014178107
## 2 2023 0.087 0.03281914 2.5261e+10 0.9901360 0.009864026
## 3 2022 0.087 0.03367064 4.7339e+10 0.9760010 0.023999047
## 4 2021 0.087 0.03963113 5.3551e+10 0.9744756 0.025524380
## 5 2020 0.087 0.03849404 5.7422e+10 0.9642483 0.035751707
## WACC
## 1 0.08625623
## 2 0.08639758
## 3 0.08555045
## 4 0.08557851
## 5 0.08497682
Richiediamo il file “metrics”, i financial statements e i balance sheets dalla database di FMI e li salviamo in un unico dataframe che ci servirà per il calcolo del nostro DCF. Abbiamo fissato i parametri di Beta, Risk Free e Market Premium secondo le attuali condizioni del titolo e del mercato.
Si calcola il costo del debito (Rd), le disponibilità immediate o quasi (cash), il debito netto (D), il market cap (E). Infine calcoliamo il WACC assumendo una tassazione del 21% (attuale, USA).
g<- mean(diff(log(rev(fcf))))
print(MSFT_WACC)
## [1] 0.08625623 0.08639758 0.08555045 0.08557851 0.08497682
print(g)
## [1] 0.1232938
Il nostro dividend growth rate, per questo caso specifico è più grande dei wacc calcolati. Per costruzione, la formula del TV di Gordon ha bisogno di una g inferiore al WACC. Per questa specifica situazione, useremo un g fisso pari alla media del settore di appartenenza
g<- 0.06
calculate_terminal_value <- function(df, g) {
FCF_n <- fcf[1]
WACC_n <- MSFT_WACC[1]
if (WACC_n <= g) {
warning(" WACC value is lower than g")
return(NA)
}
TV <- (FCF_n * (1 + g)) / (WACC_n - g)
return(TV)
}
MSFT_TV<- calculate_terminal_value(df,g)
print(MSFT_TV)
## [1] 2.990347e+12
calculate_dcf <- function(fcf, WACC, TV) {
n <- length(fcf)
discounted_fcf <- fcf / (1 + WACC)^(1:n)
discounted_TV <- TV / (1 + WACC)^n
dcf_value <- sum(discounted_fcf) + discounted_TV
return(dcf_value)
}
MSFT_DCF <- calculate_dcf(fcf, MSFT_WACC, MSFT_TV)
MSFT_DCF <- as.numeric(MSFT_DCF)
MSFT_MK <- as.numeric(key_metrics$marketCap)
if (length(MSFT_DCF) == length(MSFT_MK)) {
for (i in 1:length(MSFT_DCF)) {
if (MSFT_DCF[i] > MSFT_MK[i]) {
cat("Anno", i, "→ Microsoft è SOTTOVALUTATA secondo il DCF!\n")
} else {
cat("Anno", i, "→ Microsoft è SOPRAVVALUTATA secondo il DCF!\n")
}
}
} else {
cat(" Errore: I vettori non hanno la stessa lunghezza!\n")
}
## Anno 1 → Microsoft è SOPRAVVALUTATA secondo il DCF!
## Anno 2 → Microsoft è SOPRAVVALUTATA secondo il DCF!
## Anno 3 → Microsoft è SOTTOVALUTATA secondo il DCF!
## Anno 4 → Microsoft è SOTTOVALUTATA secondo il DCF!
## Anno 5 → Microsoft è SOTTOVALUTATA secondo il DCF!
df_MSFT <- data.frame(
Anno = seq(from = 2024, by = -1, length.out = length(MSFT_DCF)),
MSFT_DCF = round(MSFT_DCF, 2),
MSFT_Market_Cap = round(MSFT_MK, 2),
Valutazione = ifelse(MSFT_DCF > MSFT_MK, "SOTTOVALUTATA", "SOPRAVVALUTATA")
)
print(df_MSFT)
## Anno MSFT_DCF MSFT_Market_Cap Valutazione
## 1 2024 2.217246e+12 3.393961e+12 SOPRAVVALUTATA
## 2 2023 2.215960e+12 2.535661e+12 SOPRAVVALUTATA
## 3 2022 2.223682e+12 1.925198e+12 SOTTOVALUTATA
## 4 2021 2.223425e+12 2.044482e+12 SOTTOVALUTATA
## 5 2020 2.228931e+12 1.548711e+12 SOTTOVALUTATA
Ho voluto procedere step-by-by in questo processo di calcolo del DCF, a dimostrazione dell’elevata versatilità d’uso di questa API. Possiamo avere una valutazione DCF “end of the day” facendo una semplice chiamata:
DCF_MS<- FMP_CALL("discounted-cash-flow/MSFT")
print(DCF_MS)
## symbol date dcf Stock Price
## 1 MSFT 2025-03-05 389.3409 396.5
Avendo accesso ad un ampio database è possibile facilitare ed automatizzare grandi processi di valutazione e analisi finanziaria. L’utilizzo di API per ottenere più rapidamente determinati dati da server centralizzati è un potente strumento che assiste e velocizza il processo di analisi nel mondo finanziario. In questo progetto ho studiato la versatilità offerta dall’utilizzo dell’API di Financial Modelling Prep nell’analisi di diversi tipi di indicatori e valori, usandoli anche in ulteriori modellistiche esterne.
Questo studio può essere sicuramente ampliato ed applicato ad altri studi nell’ambito della finanza.